<FrameworkSwitchCourse {fw} />

# Gestionarea secvențelor multiple[[gestionarea-secvențelor-multiple]]

{#if fw === 'pt'}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_pt.ipynb"},
]} />

{:else}

<CourseFloatingBanner chapter={2}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section5_tf.ipynb"},
]} />

{/if}

{#if fw === 'pt'}
<Youtube id="M6adb1j2jPI"/>
{:else}
<Youtube id="ROxrFOEbsQE"/>
{/if}

În secțiunea anterioară, am explorat cel mai simplu caz de utilizare: realizarea de inferențe pe o singură secvență scurtă. Cu toate acestea, apar deja unele întrebări:

- Cum gestionăm secvențe multiple?
- Cum gestionăm secvențe multiple *de lungimi diferite*?
- Indicii vocabularului sunt singurele intrări care permit unui model să funcționeze bine?
- Există o secvență prea lungă?

Să vedem ce tipuri de probleme prezintă aceste întrebări și cum le putem rezolva folosind API-ul 🤗 Transformers.


## Modelele așteaptă un batch de intrări[[modelele-așteaptă-un-batch-de-intrări]]

În exercițiul anterior ați văzut cum secvențele sunt transformate în liste de numere. Să convertim această listă de numere într-un tensor și să o transmitem modelului:

{#if fw === 'pt'}
```py
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = torch.tensor(ids)
# Această linie va eșua.
model(input_ids)
```

```python out
IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)
input_ids = tf.constant(ids)
# Această linie va eșua.
model(input_ids)
```

```py out
InvalidArgumentError: Input to reshape is a tensor with 14 values, but the requested shape has 196 [Op:Reshape]
```
{/if}

Oh, nu! De ce a eșuat? Am urmat pașii din pipeline-ul din secțiunea 2.

Problema este că am trimis o singură secvență către model, în timp ce modelele 🤗 Transformers așteaptă în mod implicit mai multe propoziții. Aici am încercat să facem tot ce a făcut tokenizatorul în fundal atunci când l-am aplicat unei `secvențe`. Dar, dacă vă uitați cu atenție, veți vedea că tokenizatorul nu a convertit doar lista de ID-uri de intrare într-un tensor, ci a adăugat și o dimensiune peste aceasta:

{#if fw === 'pt'}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="pt")
print(tokenized_inputs["input_ids"])
```

```python out
tensor([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,
          2607,  2026,  2878,  2166,  1012,   102]])
```
{:else}
```py
tokenized_inputs = tokenizer(sequence, return_tensors="tf")
print(tokenized_inputs["input_ids"])
```

```py out
<tf.Tensor: shape=(1, 16), dtype=int32, numpy=
array([[  101,  1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662,
        12172,  2607,  2026,  2878,  2166,  1012,   102]], dtype=int32)>
```
{/if}

Să încercăm din nou și să adăugăm o nouă dimensiune:

{#if fw === 'pt'}
```py
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = torch.tensor([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{:else}
```py
import tensorflow as tf
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification

checkpoint = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence = "I've been waiting for a HuggingFace course my whole life."

tokens = tokenizer.tokenize(sequence)
ids = tokenizer.convert_tokens_to_ids(tokens)

input_ids = tf.constant([ids])
print("Input IDs:", input_ids)

output = model(input_ids)
print("Logits:", output.logits)
```
{/if}

Imprimăm ID-urile de intrare, precum și logit-urile rezultate - iată rezultatul:

{#if fw === 'pt'}
```python out
Input IDs: [[ 1045,  1005,  2310,  2042,  3403,  2005,  1037, 17662, 12172,  2607, 2026,  2878,  2166,  1012]]
Logits: [[-2.7276,  2.8789]]
```
{:else}
```py out
Input IDs: tf.Tensor(
[[ 1045  1005  2310  2042  3403  2005  1037 17662 12172  2607  2026  2878
   2166  1012]], shape=(1, 14), dtype=int32)
Logits: tf.Tensor([[-2.7276208  2.8789377]], shape=(1, 2), dtype=float32)
```
{/if}

Batching-ul este acțiunea de a trimite mai multe propoziții prin model, toate odată. Dacă aveți o singură propoziție, puteți crea un lot cu o singură secvență: 

```
batched_ids = [ids, ids]
```

Acesta este un batch de două secvențe identice!

> [!TIP]
> ✏️ **Încercați!** Convertiți această listă `batched_ids` într-un tensor și treceți-o prin modelul dumneavoastră. Verificați dacă obțineți aceleași logits ca înainte (dar de două ori)!

Batching-ul permite modelului să funcționeze atunci când îi furnizați mai multe secvențe. Utilizarea mai multor secvențe este la fel de simplă ca și crearea unui lot cu o singură secvență. Există însă o a doua problemă. Atunci când încercați să combinați două (sau mai multe) propoziții, acestea pot avea lungimi diferite. Dacă ați mai lucrat vreodată cu tensori, știți că aceștia trebuie să aibă o formă dreptunghiulară, deci nu veți putea converti direct lista de ID-uri de intrare într-un tensor. Pentru a rezolva această problemă, de obicei *umplem* datele de intrare.

## Padding-ul datelor de intrare[[padding-ul-datelor-de-intrare]]

Următoarea serie de liste nu poate fi convertită într-un tensor:

```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200]
]
```

Pentru a ocoli acest lucru, vom folosi *padding-ul* pentru ca tensorii noștri să aibă o formă dreptunghiulară. Padding-ul (umplerea datelor) asigură că toate propozițiile noastre au aceeași lungime prin adăugarea unui cuvânt special numit *padding token* la propozițiile cu mai puține valori. De exemplu, dacă aveți 10 propoziții cu 10 cuvinte și 1 propoziție cu 20 de cuvinte, padding-ul va asigura că toate propozițiile au 20 de cuvinte. În exemplul nostru, tensorul rezultat arată astfel:

```py no-format
padding_id = 100

batched_ids = [
    [200, 200, 200],
    [200, 200, padding_id],
]
```

ID-ul token-ului de padding poate fi găsit în `tokenizer.pad_token_id`. Să-l folosim și să trimitem cele două propoziții prin model în mod separat și grupate împreună:

{#if fw === 'pt'}
```py no-format
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(torch.tensor(sequence1_ids)).logits)
print(model(torch.tensor(sequence2_ids)).logits)
print(model(torch.tensor(batched_ids)).logits)
```

```python out
tensor([[ 1.5694, -1.3895]], grad_fn=<AddmmBackward>)
tensor([[ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
tensor([[ 1.5694, -1.3895],
        [ 1.3373, -1.2163]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint)

sequence1_ids = [[200, 200, 200]]
sequence2_ids = [[200, 200]]
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

print(model(tf.constant(sequence1_ids)).logits)
print(model(tf.constant(sequence2_ids)).logits)
print(model(tf.constant(batched_ids)).logits)
```

```py out
tf.Tensor([[ 1.5693678 -1.3894581]], shape=(1, 2), dtype=float32)
tf.Tensor([[ 0.5803005  -0.41252428]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[ 1.5693681 -1.3894582]
 [ 1.3373486 -1.2163193]], shape=(2, 2), dtype=float32)
```
{/if}

Este ceva în neregulă cu logit-urile din predicțiile noastre grupate: al doilea rând ar trebui să fie identic cu logit-urile pentru a doua propoziție, dar avem valori complet diferite!

Acest lucru se datorează faptului că principala caracteristică a modelelor Transformer sunt straturile de atenție care *contextualizează* fiecare token. Acestea vor lua în considerare token-urile de umplutură, deoarece se ocupă de toate token-urile unei secvențe. Pentru a obține același rezultat atunci când trecem propoziții individuale de diferite lungimi prin model sau atunci când trecem un batch cu aceleași propoziții și același umplutură aplicată, trebuie să spunem acelor straturi de atenție să ignore token-urile de umplutură. Acest lucru se realizează prin utilizarea unei măști de atenție (attention mask).

## Attention masks(măști de atenție)[[attention-masks]]

*Măștile de atenție* sunt tensori cu exact aceeași formă ca tensorul ID-urilor de intrare, completate cu 0 și 1: valorile 1 indică faptul că ar trebui să se acorde atenție token-urilor corespunzătoare, iar valorile 0 indică faptul că nu ar trebui să se acorde atenție token-urilor corespunzătoare (adică acestea ar trebui ignorate de straturile de atenție ale modelului).

Să completăm exemplul anterior cu o mască de atenție:

{#if fw === 'pt'}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask))
print(outputs.logits)
```

```python out
tensor([[ 1.5694, -1.3895],
        [ 0.5803, -0.4125]], grad_fn=<AddmmBackward>)
```
{:else}
```py no-format
batched_ids = [
    [200, 200, 200],
    [200, 200, tokenizer.pad_token_id],
]

attention_mask = [
    [1, 1, 1],
    [1, 1, 0],
]

outputs = model(tf.constant(batched_ids), attention_mask=tf.constant(attention_mask))
print(outputs.logits)
```

```py out
tf.Tensor(
[[ 1.5693681  -1.3894582 ]
 [ 0.5803021  -0.41252586]], shape=(2, 2), dtype=float32)
```
{/if}

Acum obținem aceeași logits pentru a doua propoziție din batch.

Observăm cum ultima valoare a celei de-a doua secvențe este un ID de padding, care este o valoare 0 în masca de atenție.

> [!TIP]
> ✏️ **Încercați!** Aplicați manual tokenizarea pe cele două propoziții utilizate în secțiunea 2 ("I've been waiting for a HuggingFace course my whole life." și "I hate this so much!"). Treceți-le prin model și verificați dacă obțineți aceeași logiți ca în secțiunea 2. Acum grupați-le împreună folosind token-ul de padding, apoi creați masca de atenție corespunzătoare. Verificați dacă obțineți aceleași rezultate atunci când parcurgeți modelul!

## Secvențe mai lungi[[secvențe-mai-lungi]]

Cu modelele Transformer, există o limită a lungimii secvențelor pe care le putem transmite modelelor. Majoritatea modelelor gestionează secvențe de până la 512 sau 1024 de token-uri și se vor bloca atunci când li se cere să proceseze secvențe mai lungi. Există două soluții la această problemă:

- Utilizați un model cu o lungime de secvență acceptată mai mare.
- Trunchiați secvențele.

Modelele au diferite lungimi de secvență acceptate, iar unele sunt specializate în tratarea secvențelor foarte lungi. [Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) este un exemplu, iar altul este [LED](https://huggingface.co/docs/transformers/model_doc/led). Dacă lucrați la o sarcină care necesită secvențe foarte lungi, vă recomandăm să aruncați o privire la aceste modele.

În caz contrar, vă recomandăm să vă trunchiați secvențele prin specificarea parametrului `max_sequence_length`:
```py
sequence = sequence[:max_sequence_length]
```
